import React, { useState, useRef, useEffect, Fragment } from 'react'
import Functionpanel from './Functionpanel'
import Emjoin from './emjjoin/index'
import './index.less'
import { Overlay, Button, Toast, NavBar, Icon, ImagePreview } from 'react-vant'
import Shot from './shot/index'
import { socket } from '../../../../utils/websocket'
import request from '../../../../utils/request'
import upload from '../../../../utils/upload'
//控制手指移动
let timeOutEvent;

function ChatPage(props) {
    //底部input的值
    const inputVal = useRef();
    // 控制是语音还是键盘
    const [isShowkeyboard, setIsShowkeyboard] = useState(false)
    //控制功能面板的显示与隐藏
    const [showPopup, setShowPopup] = useState(false);
    //控制表情的显示与隐藏
    const [showPopup1, setShowPopup1] = useState(false);
    //控制遮罩层是否显示与隐藏
    const [show, setShow] = useState(false);
    //控制footer的上滑与回底
    const footerBar = useRef()
    //控制拍摄的显示与隐藏
    const [isShowShot, setIsShowShot] = useState(false)
    //消息列表滚动
    const msgGoTop = useRef()
    //消息列表
    const [messageList, setMessageList] = useState([])
    //控制图片预览
    const [visible, setVisible] = useState(false);
    //图片预览数组
    const [Imgs, setImage] = useState([])
    const [EmojiList] = useState(["微笑",
        "撇嘴",
        "色",
        "发呆",
        "得意",
        "流泪",
        "害羞",
        "闭嘴",
        "睡",
        "大哭",
        "尴尬",
        "发怒",
        "调皮",
        "呲牙",
        "惊讶",
        "难过",
        "酷",
        "冷汗",
        "抓狂",
        "吐",
        "偷笑",
        "可爱",
        "白眼",
        "傲慢",
        "饥饿",
        "困",
        "惊恐",
        "流汗",
        "憨笑",
        "大兵",
        "奋斗",
        "咒骂",
        "疑问",
        "嘘",
        "晕",
        "折磨",
        "衰",
        "骷髅",
        "敲打",
        "再见",
        "擦汗",
        "抠鼻",
        "鼓掌",
        "糗大了",
        "坏笑",
        "左哼哼",
        "右哼哼",
        "哈欠",
        "鄙视",
        "委屈",
        "快哭了",
        "阴险",
        "亲亲",
        "吓",
        "可怜",
        "菜刀",
        "西瓜",
        "啤酒",
        "篮球",
        "乒乓",
        "咖啡",
        "饭",
        "猪头",
        "玫瑰",
        "凋谢",
        "示爱",
        "爱心",
        "心碎",
        "蛋糕",
        "闪电",
        "炸弹",
        "刀",
        "足球",
        "瓢虫",
        "便便",
        "月亮",
        "太阳",
        "礼物",
        "拥抱",
        "强",
        "弱",
        "握手",
        "胜利",
        "抱拳",
        "勾引",
        "拳头",
        "差劲",
        "爱你",
        "NO",
        "OK",
        "爱情",
        "飞吻",
        "跳跳",
        "发抖",
        "怄火",
        "转圈",
        "磕头",
        "回头",
        "跳绳",
        "挥手",
        "激动",
        "街舞",
        "献吻",
        "左太极",
        "右太极",
    ])
    useEffect(async () => {
        //获取localStorage本地缓存的登录信息
        let fromId = JSON.parse(localStorage.getItem('token'))
        //获取聊天数据方法
        getMessageList()
        //初始化socket
        socket.fromId = `?user=${fromId.info_id}`
        socket.init()
        socket.websock.onmessage = function (messages) {
            let message = JSON.parse(messages.data)
            console.log(message, '9846532');
            getMessageList()
        }
        //监听消息内容自动滚动底部
        msgGoTop.current.scrollIntoView({ block: 'end', behavior: 'smooth' })
    }, [])

    //获取聊天信息方法
    const getMessageList = async () => {
        //获取localStorage本地缓存的登录信息
        let fromId = JSON.parse(localStorage.getItem('token'))
        //定义要获取的人的聊天记录标识
        let objs = {
            from_id: fromId.info_id,
            to_id: props.location.state.toId,
        }
        //获取后台MySQL聊天记录
        let messageList = await request.post('/JFChatMsg/getdata', objs)
        setMessageList(messageList.data)
    }
    //点击控制语音或键盘
    const isRecord = () => {
        setIsShowkeyboard(!isShowkeyboard)
    }
    const [IMG, setImg] = useState()
    //发送消息
    const sendMsg = (e) => {
        if (e.keyCode === 13) {
            if (!inputVal.current.value) {
                Toast.info({ message: '不能发送空内容哦' });
                return
            }
            // EmojiList.forEach((item, index) => {
            //     item = "[[" + EmojiList[index] + "]]"
            //     if (item === inputVal.current.value) {
            //         inputVal.current.value = 'https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/' + index + '.gif'
            //     }
            // })
            // console.log(IMG, '--');
            //定义要发送的内容
            let objs = {
                to_id: props.location.state.toId,
                msg: inputVal.current.value,
                headImg: "https://pic3.zhimg.com/80/v2-437f4dc41f0f972f31921a228641cf9e_720w.jpg?source=1940ef5c",
                name: props.location.state.remark
            }
            //向后台发送消息
            socket.send(objs)
            //异步方法（解决实时更新问题）
            setTimeout(() => {
                getMessageList()
            }, 100)
            //监听消息内容自动滚动底部
            msgGoTop.current.scrollIntoView({ block: 'end', behavior: 'smooth' })

            inputVal.current.value = ''
        }
    }
    const [mediaNode, setMediaNode] = useState()
    const [jsNode, setjsNode] = useState()
    const [mediaStream, setM] = useState()
    function record() {
        window.navigator.mediaDevices.getUserMedia({
            audio: true
        }).then(mediaStream => {
            beginRecord(mediaStream);
            setM(mediaStream)
        }).catch(err => {
            // 如果用户电脑没有麦克风设备或者用户拒绝了，或者连接出问题了等
            // 这里都会抛异常，并且通过err.name可以知道是哪种类型的错误 
            console.error(err);
        });
    }
    function beginRecord(mediaStream) {
        let audioContext = new (window.AudioContext || window.webkitAudioContext);
        let mediaNode = audioContext.createMediaStreamSource(mediaStream);

        setMediaNode(mediaNode)
        // 创建一个jsNode
        let jsNode = createJSNode(audioContext);
        // 需要连到扬声器消费掉outputBuffer，process回调才能触发
        // 并且由于不给outputBuffer设置内容，所以扬声器不会播放出声音
        jsNode.connect(audioContext.destination);
        jsNode.onaudioprocess = onAudioProcess;
        // 把mediaNode连接到jsNode
        mediaNode.connect(jsNode);
        setjsNode(jsNode)
    }
    const [leftDataList] = useState([])
    const [rightDataList] = useState([])
    function onAudioProcess(event) {
        let audioBuffer = event.inputBuffer;
        let leftChannelData = audioBuffer.getChannelData(0),
            rightChannelData = audioBuffer.getChannelData(1);
        // 需要克隆一下
        leftDataList.push(leftChannelData.slice(0));
        rightDataList.push(rightChannelData.slice(0));
    }
    function createJSNode(audioContext) {
        const BUFFER_SIZE = 4096;
        const INPUT_CHANNEL_COUNT = 2;
        const OUTPUT_CHANNEL_COUNT = 2;
        // createJavaScriptNode已被废弃
        let creator = audioContext.createScriptProcessor || audioContext.createJavaScriptNode;
        creator = creator.bind(audioContext);
        return creator(BUFFER_SIZE,
            INPUT_CHANNEL_COUNT, OUTPUT_CHANNEL_COUNT);
    }
    function mergeArray(list) {
        let length = list.length * list[0].length;
        let data = new Float32Array(length),
            offset = 0;
        for (let i = 0; i < list.length; i++) {
            data.set(list[i], offset);
            offset += list[i].length;
        }
        return data;
    }
    // 交叉合并左右声道的数据
    function interleaveLeftAndRight(left, right) {
        let totalLength = left.length + right.length;
        let data = new Float32Array(totalLength);
        for (let i = 0; i < left.length; i++) {
            let k = i * 2;
            data[k] = left[i];
            data[k + 1] = right[i];
        }
        return data;
    }
    function createWavFile(audioData) {
        const WAV_HEAD_SIZE = 44;
        let buffer = new ArrayBuffer(audioData.length * 2 + WAV_HEAD_SIZE),
            // 需要用一个view来操控buffer
            view = new DataView(buffer);
        // 写入wav头部信息
        // RIFF chunk descriptor/identifier
        writeUTFBytes(view, 0, 'RIFF');
        // RIFF chunk length
        view.setUint32(4, 44 + audioData.length * 2, true);
        // RIFF type
        writeUTFBytes(view, 8, 'WAVE');
        // format chunk identifier
        // FMT sub-chunk
        writeUTFBytes(view, 12, 'fmt ');
        // format chunk length
        view.setUint32(16, 16, true);
        // sample format (raw)
        view.setUint16(20, 1, true);
        // stereo (2 channels)
        view.setUint16(22, 2, true);
        // sample rate
        view.setUint32(24, 44100, true);
        // byte rate (sample rate * block align)
        view.setUint32(28, 44100 * 2, true);
        // block align (channel count * bytes per sample)
        view.setUint16(32, 2 * 2, true);
        // bits per sample
        view.setUint16(34, 16, true);
        // data sub-chunk
        // data chunk identifier
        writeUTFBytes(view, 36, 'data');
        // data chunk length
        view.setUint32(40, audioData.length * 2, true);

        // 写入PCM数据
        let length = audioData.length;
        let index = 44;
        let volume = 1;
        for (let i = 0; i < length; i++) {
            view.setInt16(index, audioData[i] * (0x7FFF * volume), true);
            index += 2;
        }
        return buffer;
    }
    function writeUTFBytes(view, offset, string) {
        var lng = string.length;
        for (var i = 0; i < lng; i++) {
            view.setUint8(offset + i, string.charCodeAt(i));
        }
    }
    const audios = useRef()
    const SIZE = 1024 * 1024 * 10 //100MB
    async function playRecord(arrayBuffer) {
        let blob = new Blob([new Uint8Array(arrayBuffer)], { type: "mp3" });
        console.log(blob, '[][][][][]');
        //上传录音文件
        // let blobUrl = URL.createObjectURL(blob);
        let files = new File([blob], `${Date.now()}.mp3`, {
            type: "audio/mp3",
            lastModified: Date.now(),
        });
        if (!files) return
        //创建文件切片
        const createFileChunks = (files, size = SIZE) => {
            const fileChunks = []
            for (let cur = 0; cur < files.size; cur += size) {
                fileChunks.push(files.slice(cur, cur + size))
            }
            return fileChunks;
        }

        //上传切片
        const uploadFileChunks = async (fileChunks, filename) => {
            const formDataList = fileChunks.map((chunk, index) => {
                let formData = new FormData();
                formData.append('filename', filename);
                formData.append('hash', index);
                formData.append('chunk', chunk);
                return formData
            });
            const axiosList = formDataList.map((formDataItem) => {
                request.post('/JFChatMsg/upload', formDataItem).then(res => {
                    console.log(res);
                })
            })

            //并发上传
            await Promise.all(axiosList)
        }

        //合并切片
        const mergeFileChunks = async (filename) => {
            request.post('/JFChatMsg/merge', { filename }).then(res => {
                //定义要发送的内容
                let objs = {
                    to_id: props.location.state.toId,
                    msg: res.data.url,
                    headImg: "https://pic3.zhimg.com/80/v2-437f4dc41f0f972f31921a228641cf9e_720w.jpg?source=1940ef5c",
                    name: props.location.state.remark
                }
                //向后台发送消息
                socket.send(objs)
            })
        }

        try {
            const fileChunks = createFileChunks(files)
            await uploadFileChunks(fileChunks, files.name)
            await mergeFileChunks(files.name)
            console.log('上传成功');
        } catch (error) {
            console.log('上传失败');
        }
        //异步方法（解决实时更新问题）
        setTimeout(() => {
            getMessageList()
        }, 100)
    }
    function stopRecord() {
        // 停止录音
        mediaStream.getAudioTracks()[0].stop();
        jsNode.disconnect();
        mediaNode.disconnect()
        let leftData = mergeArray(leftDataList),
            rightData = mergeArray(rightDataList);
        console.log(leftData, rightData, '[]');
        let allData = interleaveLeftAndRight(leftData, rightData);
        let wavBuffer = createWavFile(allData);
        playRecord(wavBuffer);
    }
    //手指开始事件
    const touchStart = () => {
        timeOutEvent = setTimeout(() => {
            timeOutEvent = 0;
            console.log('你长按了');
            setShow(true)
            record()
        }, 500)
    }

    //手指移动事件
    const touchMove = () => {
        clearTimeout(timeOutEvent)
        timeOutEvent = 0;
    }

    //手指抬起结束事件
    const touchEnd = () => {
        clearTimeout(timeOutEvent);
        //关闭语音录音
        stopRecord()
        setShow(false)
        if (timeOutEvent != 0) {
            console.log('你点击了');
            stopRecord()
        }
        return false;
    }
    //main body点击关闭面板
    const close = () => {
        setShowPopup(false)
        setShowPopup1(false)
        footerBar.current.style.bottom = 0
    }

    //点击加号打开功能面板
    const openPanel = () => {


        setShowPopup(true)
        setShowPopup1(false)
        footerBar.current.style.bottom = 170 + 'px'
    }

    //点击笑脸打开表情包面版
    const openEmjoin = () => {
        setShowPopup(false)
        setShowPopup1(true)
        footerBar.current.style.bottom = 170 + 'px'
    }

    //选择表情发送
    const chooseEmoji = (EmojiList, index) => {
        inputVal.current.value += " [" + EmojiList[index] + "] "
        inputVal.current.focus()
    }
    //设置emojon表情的
    const getEmo = (item) => {
        let font =
            '<img src="https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/';
        let behind = '.gif">';

        let arr = item.split("");
        let left;
        let right;
        for (let i = 0; i < arr.length; i++) {
            if (arr[i] === "[") {
                left = i;
                arr.splice(i, 1, font);
            }
            if (arr[i] === "]") {
                right = i;
                let info = arr.slice(left + 1, right).join("");
                let num = EmojiList.findIndex((item) => {
                    return item === info;
                });
                arr.splice(i, 1, behind);
                arr.splice(left + 1, right - left - 1, num);
            }
        }
        let result = arr.join("");
        return result;
    }
    //点击查看未读消息滚动到顶部
    const goToTop = () => {
        msgGoTop.current.scrollIntoView({ block: 'end', behavior: 'smooth' })
    }

    const initExpanded = ['1'];

    //回退到上一级
    const cancel = () => {
        props.history.go(-1)
    }

    //关闭摄像头
    const cancelShot = () => {
        console.log('00000000');
        setIsShowShot(false)
    }

    return (
        <div className="chatBox">

            {/* 头部导航 */}
            <header>
                <NavBar
                    title={props.location.state.remark}
                    leftArrow
                    rightText={<Icon name="ellipsis" />}
                    onClickLeft={cancel}
                    onClickRight={() => Toast.info('按钮')}
                />
            </header>
            {/* 中间聊天 */}
            <main onClick={close}>
                <div ref={msgGoTop} >
                    {
                        messageList.map((item, index) => {
                            return <Fragment key={index}>
                                {

                                    item.from_id === JSON.parse(localStorage.getItem('token')).info_id ? <div className="rightChat">
                                        <div className="frame">
                                            {/* {
                                                item.msg.split('.')[1] === 'doc' ? <iframe className="filename"  src={item.msg} style={{width:"100%",height:"30px"}} frameborder='1' ></iframe> : null
                                            } */}
                                            {
                                                item.msg.split('.')[1] === 'mp3' ? <span style={{ width: "10%", height: "30px" }} onClick={() => {
                                                    //播放音频
                                                    audios.current.play()
                                                }} className="audioBox">
                                                    <svg style={{ fontSize: "20px" }} className='icon' aria-hidden='true'>
                                                        <use xlinkHref="#icon-yuyinshuru"></use>
                                                    </svg>
                                                    <audio ref={audios} src={item.msg} className="audio-node"></audio>
                                                </span> : item.msg.split('.')[1] === 'jpg' || item.msg.split('.')[1] === 'jpeg' ? <img onClick={() => {
                                                    Imgs[0] = item.msg
                                                    setVisible(true)
                                                }} style={{ width: "100px" }} src={item.msg} alt="" /> : item.msg.split('.')[1] === 'mp4' ? <video width="150px" height="150px" src={item.msg} autoPlay controls ></video> : (item.msg.indexOf('[') !== -1 &&
                                                    item.msg.indexOf(']') !== -1 ? <span className="rotationtiao" dangerouslySetInnerHTML={{ __html: getEmo(item.msg) }}></span> : <span className="rotationtiao">{item.msg}</span>)
                                            }
                                        </div>
                                        <img style={{ width: "40px", borderRadius: "5px" }} src={item.headImg} alt="" />
                                    </div> : <div className="leftChat">
                                            <img style={{ width: "40px", borderRadius: "5px" }} src={item.headImg} alt="" />
                                            <div className="frame">
                                                <div className="triangle"></div>
                                                {
                                                    item.msg.split('.')[1] === 'mp3' ? <span style={{ width: "10%", height: "30px" }} onClick={() => {
                                                        audios.current.play()
                                                    }} className="audioBox">
                                                        <svg style={{ fontSize: "20px" }} className='icon' aria-hidden='true'>
                                                            <use xlinkHref="#icon-yuyinshuru"></use>
                                                        </svg>
                                                        <audio ref={audios} src={item.msg} className="audio-node"></audio>
                                                    </span> : item.msg.split('.')[1] === 'jpg' || item.msg.split('.')[1] === 'jpeg' ? <img onClick={() => {
                                                        Imgs[0] = item.msg
                                                        setVisible(true)
                                                    }} style={{ width: "100px" }} src={item.msg} alt="" /> : item.msg.split('.')[1] === 'mp4' ? <video width="150px" height="150px" src={item.msg} autoPlay controls ></video> : (item.msg.indexOf('[') !== -1 &&
                                                        item.msg.indexOf(']') !== -1 ? <span className="rotationtiao" dangerouslySetInnerHTML={{ __html: getEmo(item.msg) }}></span> : <span className="rotationtiao">{item.msg}</span>)
                                                }

                                            </div>
                                        </div>
                                }
                            </Fragment>
                        })
                    }
                </div>
            </main>
            {/* 底部input框 */}
            <footer ref={footerBar}>
                <span onClick={isRecord}>
                    {
                        isShowkeyboard ? <svg className='icon' aria-hidden='true'>
                            <use xlinkHref="#icon-jianpan"></use>
                        </svg> : <svg className='icon' aria-hidden='true'>
                                <use xlinkHref="#icon-yuyin"></use>
                            </svg>
                    }
                </span>
                {
                    isShowkeyboard ? <p onTouchStart={touchStart} onTouchMove={touchMove} onTouchEnd={touchEnd} >{
                        show ? <span>上滑 取消</span> : <span>按住 说话</span>
                    }</p> : <input type="text" ref={inputVal} onKeyDown={(e) => sendMsg(e)} />
                }
                <span onClick={openEmjoin}>
                    <svg className='icon' aria-hidden='true'>
                        <use xlinkHref="#icon-biaoqingbao_px"></use>
                    </svg>
                </span>
                <span onClick={openPanel}>
                    <svg className='icon' aria-hidden='true'>
                        <use xlinkHref="#icon-zengjiatianjiajiahao"></use>
                    </svg>
                </span>
            </footer>
            {/* 展示图片预览功能 */}
            <ImagePreview
                lazyload={true}
                showIndex={false}
                visible={visible}
                onClose={() => setVisible(false)}
                images={Imgs}
            />
            {/* 控制语音显示弹框 */}
            {
                show ?
                    <Overlay visible={show} onClick={() => setShow(false)}>
                        <div className="wrapper">
                            <div className="spinner">
                                <div className="rect1"></div>
                                <div className="rect2"></div>
                                <div className="rect3"></div>
                                <div className="rect4"></div>
                                <div className="rect5"></div>
                                <div className="rect6"></div>
                                <div className="rect7"></div>
                                <div className="rect8"></div>
                            </div>
                        </div>
                    </Overlay> : null
            }
            {/* 底部功能面板 */}
            <Functionpanel ws={socket} detail={props.location.state} getMessageList={getMessageList} showPopup={showPopup} setIsShowShot={setIsShowShot} />
            {/* 表情面板 */}
            <Emjoin showPopup1={showPopup1} chooseEmoji={chooseEmoji} />
            {/* 未读消息滚动 */}
            <div className="weidu">
                <Button onClick={goToTop} plain hairline round size="small" type="primary">查看</Button>
            </div>
            {/* 摄像头 */}
            {
                isShowShot ? <Shot ws={socket} detail={props.location.state} getMessageList={getMessageList} changeShot={cancelShot} className="shotBox" /> : null
            }
        </div >
    )
}
export default ChatPage
